/*
 * Copyright 2014 JootMir Project
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Support: http://www.jootmir.org
 */
package org.jootmir.client.core.util;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.jootmir.client.core.Files;
import org.jootmir.client.core.exception.JMir2Exception;

/** 一些不好归类的方法 */
public final class Kit {
	/** log */
	private static final Logger log = Logger.getLogger(Kit.class);
	
	/**
	 * 读取适合lwjgl窗口使用的图标
	 * 
	 * @param res
	 * 			资源路径
	 * @return bytebuffer
	 */
	public static ByteBuffer imageToIcon(String res) {
		try {
			InputStream is = Files.inputStream(res);
			BufferedImage bi = ImageIO.read(is);
			is.close();
			byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
			ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
			buffer.order(ByteOrder.nativeOrder());
			int pixelCount = data.length / 4;
			for(int i = 0; i < pixelCount; ++i) {
				// 将ARGB换成RGBA
				byte r = data[i * 4 + 1];
				byte g = data[i * 4 + 2];
				byte b = data[i * 4 + 3];
				byte a = data[i * 4];
				buffer.put(r).put(g).put(b).put(a);
			}
			buffer.flip();
			return buffer;
		} catch (IOException ex) {
			JMir2Exception exception = JMir2Exception.valueOf(ex, JMir2Exception.EXCEPTION_TYPE_FILESTREAM);
			log.error(exception.getMessage(), ex);
			throw exception;
		}
	}
	
	/**
	 * 读取文件并作为图片返回
	 * 
	 * @param path
	 * 		文件路径
	 * @return 读取到的图片，如果读取失败则返回null
	 */
	public static Image image(String path) {
		try {
			return ImageIO.read(Files.inputStream(path));
		} catch (IOException e) {
			return null;
		}
	}
	
	/**
	 * 判断一个整数是否为2的幂次
	 * 
	 * @param n
	 * 		需要验证的数
	 * @return 该数是否为2的幂次
	 */
	public static boolean isPowerOfTwo(int n) {
		return (n & (n-1)) == 0;
	}
	
	/**
	 * 获取最接近的2次幂整数
	 * 
	 * @param n
	 * 		目标数
	 * @return 与该数最接近的2幂次数(大于该数)
	 */
	public static int closestPowerOfTwo(int n) {
		int t = 2;
		while(t < n)
			t *= 2;
		return t;
	}
	
	/**
	 * 从字节数组中读取整形数据
	 * 
	 * @param bytes
	 * 	数据来源
	 * @param index
	 * 	数组中获取数据的起始位置(索引从0开始，数据还原将包含给定位置) 具体规则示例参见{@link #readShort(byte[], int, boolean) readShort}
	 * @param reverse
	 * 	是否需要反转字节(只针对包含当前数据的字节数组)
	 * @return
	 * 	从字节数组指定位置4个字节还原出的短整形数值
	 */
	public static int readInt(byte[] bytes, int index, boolean reverse) {
		if(reverse)
			return (int) (((bytes[index + 3] & 0xff) << 24)  
	                | ((bytes[index + 2] & 0xff) << 16)  
	                | ((bytes[index + 1] & 0xff) << 8) 
	                | (bytes[index] & 0xff));
		else
			return (int) (((bytes[index] & 0xff) << 24)  
	                | ((bytes[index + 1] & 0xff) << 16)  
	                | ((bytes[index + 2] & 0xff) << 8) 
	                | (bytes[index + 3] & 0xff));
	}
	
	/**
	 * 从字节数组中读取断整形数据
	 * 
	 * @param bytes
	 * 	数据来源
	 * @param index
	 * 	数组中获取数据的起始位置(索引从0开始，数据还原将包含给定位置)
	 * <br>
	 * 	例如给定[0x01,0x02,0x03,0x04],2,true作为参数则函数会将[0x04,0x03]还原为短整形数值并返回
	 * @param reverse
	 * 	是否需要反转字节(只针对包含当前数据的字节数组)
	 * @return
	 * 	从字节数组指定位置2个字节还原出的短整形数值
	 */
	public static short readShort(byte[] bytes, int index, boolean reverse) {
		if(reverse)
			return (short) ((bytes[index + 1] << 8) | (bytes[index] & 0xff));
		else
			return (short) ((bytes[index] << 8) | (bytes[index + 1] & 0xff));
	}

	/**
	 * 判断短整型数据最高位是否为1
	 * 
	 * @param target
	 * 	目标数据
	 * @return
	 * 	true表示该数据最高位为1，false表示该数据最高位为0
	 */
	public static boolean is1AtTopDigit(short target) {
		//return (target & 0b1000_0000_0000_0000) == 0b1000_0000_0000_0000;
		return (target & 0x8000) == 0x8000;
	}

	/**
	 * 判断字节数据最高位是否为1
	 * 
	 * @param target
	 * 	目标数据
	 * @return
	 * 	true表示该数据最高位为1，false表示该数据最高位为0
	 */
	public static boolean is1AtTopDigit(byte target) {
		//return (target & 0x1000_0000) == 0x1000_0000;
		return (target & 0x80) == 0x80;
	}
	
	/**
	 * 将颜色数换算成字节位
	 * 
	 * @param colorCount
	 * 	颜色数
	 * @return
	 * 	字节位
	 */
	public static int colorCountToBitCount(int colorCount) {
		if(colorCount == 256) return 8;
		else if(colorCount == 65536) return 16;
		else if(colorCount == 16777216) return 24;
		else return 32;
	}
	
	/**
	 * 对于bmp图片填充字节进行补足
	 * 
	 * @param bitCount
	 * 	每行图片色彩值字节位数(bit)
	 * @return
	 * 	每行图片色彩数据占字节数(byte)
	 */
	public static int widthBytes(int bitCount) {
		return (bitCount + 31) / 32 * 4;
	}
	
	/**
	 * 计算bmp图片逐行读取时需要跳过的字节数
	 * <br>
	 * 即用该行实际占用的字节数减去真正占用的字节数
	 * 
	 * @param bit
	 * 	位深度
	 * @param width
	 * 	图片宽度
	 * @return
	 * 	读取某行数据时需要跳过的字节数
	 * @see #widthBytes(int)
	 */
	public static int skipBytes(int bit, int width) {
		return widthBytes(bit * width) - width * (bit / 8);
	}
}